home *** CD-ROM | disk | FTP | other *** search
/ Ian & Stuart's Australian Mac 1993 September / September 93.iso / Archives / Utilities / System / Extension / CountPatches / CountPatches.c < prev    next >
C/C++ Source or Header  |  1993-06-17  |  10KB  |  312 lines

  1. #include <Types.h>
  2. #include <Traps.h>
  3. #include <SetupA4.h>
  4. #include <Files.h>
  5.  
  6. #define _NSetTrapAddress    0xA247    /* from Think Reference; not defined in Traps.h */
  7.  
  8. /*******************************************************************************
  9.  
  10.     Typedefs.
  11.  
  12. *******************************************************************************/
  13. typedef pascal short (*HOpenResFileProc)(short vRefNum, 
  14.                                          long dirID, 
  15.                                          ConstStr255Param fn, 
  16.                                          char    permission);
  17. typedef pascal void (*CloseResFileProc)(short refNum);
  18. typedef pascal void (*NSetTrapAddressProc)(long trapAddr, short trapNum, short trapType);
  19. typedef pascal void (*LaunchProc)(void);
  20.  
  21. /*******************************************************************************
  22.  
  23.     Globals.
  24.  
  25. *******************************************************************************/
  26. HOpenResFileProc    gOldHOpenResFileAddress;
  27. CloseResFileProc    gOldCloseResFileAddress;
  28. NSetTrapAddressProc    gOldNSetTrapAddressAddress;
  29. LaunchProc            gOldLaunchAddress;
  30.  
  31. short                gCounter;
  32. Str255                gInitName;
  33.  
  34. /*******************************************************************************
  35.  
  36.     Function prototypes.  Each trap patched should have a new function with 
  37.                           the same parms as the original trap.
  38.  
  39. *******************************************************************************/
  40.  
  41. void        main(void);
  42. pascal void DrawIt(StringPtr theString);
  43. StringPtr     NumToPStr(short n);                    /* from NumToPStr.c */
  44. StringPtr    StrPCat(StringPtr a, StringPtr b);    /* from NumToPStr.c */
  45.  
  46. /*** HOpenResFile ***/
  47. pascal short    MyHOpenResFile(short vRefNum, 
  48.                                long dirID, 
  49.                                ConstStr255Param fn, 
  50.                                char permission);
  51. /*** CloseResFile ***/
  52. pascal void    MyCloseResFile(short refNum);
  53. /*** NSetTrapAddress ***/
  54. pascal void    MyNSetTrapAddress(long trapAddr, short trapNum, short trapType);
  55. /*** Launch ***/
  56. pascal void    MyLaunch(void);
  57.  
  58. /*******************************************************************************
  59.  
  60.     main
  61.  
  62.     When INITs are loaded, the operating system jumps to the first byte in the
  63.     resource to execute them. Under THINK C, the compiler adds a little
  64.     snippet of code at the beginning of the INIT that jumps to main(), which
  65.     means that main() can appear anywhere in the source. Under MPW, this isn’t
  66.     done for you, so you have to make sure that main() is the first procedure
  67.     in your source code. 
  68.  
  69.     In order for INITs to stay resident, they must be loaded into the System
  70.     heap. Because they contain executable instructions that can be called at
  71.     any time, the INIT resource should be locked. Since they’ll remain locked
  72.     during the entire time the computer is on, they should be loaded as low in
  73.     the heap as possible to prevent fragmentation. Setting the resSysHeap and
  74.     resLocked bits of our INIT resource will do this for us. However, none of
  75.     this prevents our INIT resource from being removed from memory as soon as
  76.     the file it’s in is closed. Therefore, the first thing our main() routine
  77.     does detach the INIT from the resource file. 
  78.  
  79.     Next, we plug ourselves into the HOpenResFile() routine. This is done in two
  80.     steps. First, we get the address of the current HOpenResFile() routine and save
  81.     it. Then we install the address of our own custom routine. 
  82.  
  83. *******************************************************************************/
  84. void    main()
  85. {
  86.     Ptr    ourAddress;
  87.  
  88.     RememberA0();
  89.     SetUpA4();
  90.  
  91.     asm {
  92.         move.l    A0, ourAddress        ; A0 points to the beginning of the
  93.                                     ; INIT, courtesy of the THINK glue
  94.         }
  95.     DetachResource(RecoverHandle(ourAddress));
  96.  
  97.     gOldHOpenResFileAddress = (HOpenResFileProc) GetToolTrapAddress(_HOpenResFile);
  98.     SetToolTrapAddress((long) MyHOpenResFile, _HOpenResFile);
  99.     gOldCloseResFileAddress = (CloseResFileProc) GetToolTrapAddress(_CloseResFile);
  100.     SetToolTrapAddress((long) MyCloseResFile, _CloseResFile);
  101.     gOldNSetTrapAddressAddress = (NSetTrapAddressProc) GetOSTrapAddress(_NSetTrapAddress);
  102.     SetOSTrapAddress((long) MyNSetTrapAddress, _NSetTrapAddress);
  103.     gOldLaunchAddress = (LaunchProc) GetToolTrapAddress(_Launch);
  104.     SetToolTrapAddress((long) MyLaunch, _Launch);
  105.     RestoreA4();
  106. }
  107.  
  108. /*******************************************************************************
  109.  
  110.     MyHOpenResFile
  111.  
  112.     This the patch that gets called whenever any application calls HOpenResFile.
  113.     We check if they are opening an INIT.  If so, we want to do our thing.
  114.  
  115.     Under the THINK environments, you are allowed to have global variables in
  116.     standalone code as long as you call SetUpA4() first. Since we’ve stored
  117.     the address of the original HOpenResFile routine in a global, the first we do
  118.     is call SetUpA4(). Then we call the original HOpenResFile so that it can do its
  119.     processing. 
  120.  
  121.     Next, it’s time for our custom code to step in. 
  122.     
  123. *******************************************************************************/
  124. pascal short MyHOpenResFile(short vRefNum, 
  125.                             long dirID, 
  126.                             ConstStr255Param fn, 
  127.                             char permission)
  128. {
  129.     short        result;
  130.     FInfo        fndrInfo;
  131.     OSErr        iErr;
  132.  
  133.     SetUpA4();
  134.  
  135.     gCounter = -1;            /* -1 means don't track it */
  136.     
  137.     iErr = HGetFInfo(vRefNum, dirID, fn, &fndrInfo);
  138.     if ( (iErr == noErr) && 
  139.          (fndrInfo.fdType == 'INIT') || 
  140.          (fndrInfo.fdType == 'cdev') ) {
  141.         gCounter = 0;            /* clear our global counter */
  142.         BlockMove(fn, gInitName, *fn+1);
  143.     }
  144.     
  145.     result = gOldHOpenResFileAddress(vRefNum, dirID, fn, permission);
  146.  
  147.     RestoreA4();
  148.  
  149.     return result;
  150. }
  151.  
  152.  
  153. /*******************************************************************************
  154.  
  155.     MyCloseResFile
  156.  
  157.     This the patch that gets called whenever any application calls CloseResFile.
  158.     We check if they are opening an INIT.  If so, we want to do our thing.
  159.  
  160.     Under the THINK environments, you are allowed to have global variables in
  161.     standalone code as long as you call SetUpA4() first. Since we’ve stored
  162.     the address of the original CloseResFile routine in a global, the first we do
  163.     is call SetUpA4(). Then we call the original CloseResFile so that it can do its
  164.     processing. 
  165.  
  166.     Next, it’s time for our custom code to step in. 
  167.     
  168. *******************************************************************************/
  169. pascal void MyCloseResFile(short refNum)
  170. {
  171.     StringPtr    numString;
  172.     SetUpA4();
  173.  
  174.     if (gCounter != -1) {
  175.         numString = NumToPStr(gCounter);
  176.         numString = StrPCat(gInitName, NumToPStr(gCounter));
  177.         DrawIt(numString);
  178.         while (!Button()) {} ;
  179.         while (Button()) {};
  180.     }
  181.     gOldCloseResFileAddress(refNum);
  182.  
  183.     RestoreA4();
  184. }
  185.  
  186.  
  187. /*******************************************************************************
  188.  
  189.     MyNSetTrapAddress
  190.  
  191.     This the patch that gets called whenever any application calls NSetTrapAddress.
  192.     We check if they are opening an INIT.  If so, we want to do our thing.
  193.  
  194.     Under the THINK environments, you are allowed to have global variables in
  195.     standalone code as long as you call SetUpA4() first. Since we’ve stored
  196.     the address of the original NSetTrapAddress routine in a global, the first we do
  197.     is call SetUpA4(). Then we call the original NSetTrapAddress so that it can do its
  198.     processing. 
  199.  
  200.     Next, it’s time for our custom code to step in. 
  201.     
  202. *******************************************************************************/
  203. pascal void    MyNSetTrapAddress(long trapAddr, short trapNum, short trapType)
  204. {
  205.     NSetTrapAddressProc nextLink;
  206.     short trapWord;
  207.     short callerTrapWord;    // the trap word used to make this call is in d1
  208.     
  209.     asm {
  210.         movem.l    a0-a5/d0-d7,-(sp)
  211.         move.w    d0,trapWord
  212.         move.w    d1,callerTrapWord
  213.     }
  214.     
  215.     SetUpA4();
  216.     nextLink = gOldNSetTrapAddressAddress;
  217.     
  218.     if (gCounter != -1)
  219.         gCounter++;
  220.         
  221.     asm{
  222.         move.l    (sp)+,a4            ; same as RestoreA4()
  223.         movem.l    (sp)+,a0-a5/d0-d7
  224.         move.l    nextLink,a1
  225.         unlk    a6
  226.         jmp        (a1)
  227.     }
  228. }
  229.  
  230.  
  231.  
  232. /*******************************************************************************
  233.  
  234.     MyLaunch
  235.  
  236.     This the patch that gets called whenever any application calls Launch.
  237.  
  238.     Under the THINK environments, you are allowed to have global variables in
  239.     standalone code as long as you call SetUpA4() first. Since we’ve stored
  240.     the address of the original Launch routine in a global, the first we do
  241.     is call SetUpA4(). Then we call the original Launch so that it can do its
  242.     processing. 
  243.  
  244.     Next, it’s time for our custom code to step in. 
  245.         
  246. *******************************************************************************/
  247. pascal void MyLaunch()
  248. {
  249.     LaunchProc nextLink;
  250.     
  251.     asm {
  252.         movem.l    a0-a5/d0-d7,-(sp)
  253.     }
  254.     
  255.     SetUpA4();
  256.     nextLink = gOldLaunchAddress;
  257.     
  258.     SetToolTrapAddress((long) gOldHOpenResFileAddress, _HOpenResFile);
  259.     SetToolTrapAddress((long) gOldCloseResFileAddress, _CloseResFile);
  260.     SetOSTrapAddress((long) gOldNSetTrapAddressAddress, _NSetTrapAddress);
  261.     SetToolTrapAddress((long) gOldLaunchAddress, _Launch);
  262.  
  263.     asm{
  264.         move.l    (sp)+,a4            ; same as RestoreA4()
  265.         movem.l    (sp)+,a0-a5/d0-d7
  266.         move.l    nextLink,a1
  267.         unlk    a6
  268.         jmp        (a1)
  269.     }
  270. }
  271.  
  272.  
  273.  
  274. /*******************************************************************************
  275.  
  276.     DrawIt
  277.     
  278.     Initialize a QuickDraw
  279.  
  280. *******************************************************************************/
  281. #include <QuickDraw.h>
  282.  
  283. typedef struct QuickDraw {       /* struct to hold QuickDraw globals */
  284.   char private[76];
  285.   long randSeed;
  286.   BitMap screenBits;
  287.   Cursor arrow;
  288.   Pattern dkGray;
  289.   Pattern ltGray;
  290.   Pattern gray;
  291.   Pattern black;
  292.   Pattern white;
  293.   GrafPtr thePort;
  294. } QuickDraw;
  295.  
  296. pascal void DrawIt(StringPtr theString)
  297. {
  298.   GrafPort myPort;              /* port we draw into */
  299.   QuickDraw qdGlobals;             /* our own personal QD globals... */
  300.   Rect        theRect = {145, 240, 165, 440};
  301.   
  302.   SetUpA4();
  303.   InitGraf(&qdGlobals.thePort);    /* initialize our qdGlobals structure */
  304.   OpenPort(&myPort);
  305.   SetPort(&myPort);
  306.   InitFonts();
  307.  
  308.   MoveTo(240,160);
  309.   EraseRect(&theRect);
  310.   DrawString(theString);
  311.   RestoreA4();
  312. }